const WebSocket = require('ws');
const service = require('./data');
const path = require('path');

const originalLog = console.log;
console.log = function() {
  const date = new Date();
  const pad = (num) => String(num).padStart(2, '0');
  const ms = String(date.getMilliseconds()).padStart(3, '0');
  
  const timestamp = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${ms}`;
  
  originalLog.apply(console, [`[${timestamp}]`, ...arguments]);
};

// 接收启动参数作为端口号，默认8081
const PORT = process.argv[2] || 8081;
const server = new WebSocket.Server({ port: PORT });

const SEND_TYPE_REG = '1001'; // 注册后发送用户id
const SEND_TYPE_ROOM_INFO = '1002'; // 发送房间信息
const SEND_TYPE_JOINED_ROOM = '1003'; // 加入房间后的通知，比如对于新进用户，Ta需要开始连接其他人
const SEND_TYPE_NEW_CANDIDATE = '1004'; // offer
const SEND_TYPE_NEW_CONNECTION = '1005'; // new connection
const SEND_TYPE_CONNECTED = '1006'; // new connection
const SEND_TYPE_NICKNAME_UPDATED = '1007'; // 昵称更新通知

const RECEIVE_TYPE_NEW_CANDIDATE = '9001'; // offer
const RECEIVE_TYPE_NEW_CONNECTION = '9002'; // new connection
const RECEIVE_TYPE_CONNECTED = '9003'; // joined
const RECEIVE_TYPE_KEEPALIVE = '9999'; // keep-alive
const RECEIVE_TYPE_UPDATE_NICKNAME = '9004'; // 更新昵称请求

// 从room_pwd.json中获取房间密码
// let roomPwd = { };
// try {
//   // 获取可执行程序所在目录
//   const exePath = process.pkg ? path.dirname(process.execPath) : __dirname;
//   roomPwdConfig = require(path.join(exePath, 'room_pwd.json'));
//   let roomIds = [];
//   roomPwdConfig.forEach(item => {
//     roomIds.push(item.roomId);
//     roomPwd[item.roomId] = { "pwd": item.pwd, "turns": item.turns };
//   });
//   console.log(`加载房间数据: ${roomIds.join(',')}`);
// } catch (e) {
//   console.error('Failed to load room_pwd.json');
// }
let turn = null;
let apiKey = null;
try {
  // 获取可执行程序所在目录
  const exePath = process.pkg ? path.dirname(process.execPath) : __dirname;
  appConfig = require(path.join(exePath, 'config.json'));
  appConfig.forEach(item => {
    turn = item.turns
    apiKey = item.apiKey
  });
  console.log(`加载turns数据: ${turn}`);
  console.log(`加载apiKey数据: ${apiKey}`);
} catch (e) {
  console.error('Failed to load config.json');
}
let roomPwd = {}; // 直接在内存中维护房间信息
console.log(`初始化房间存储，当前房间数: 0`);

console.log(`Signaling server running on ws://localhost:${PORT}`);

server.on('connection', (socket, request) => {
  const ip = request.headers['x-forwarded-for'] ?? request.headers['x-real-ip'] ?? socket._socket.remoteAddress.split("::ffff:").join("");

  const urlWithPath = request.url.split('/')
  let roomId = null;
  let pwd = null;
  if (urlWithPath.length > 1 && urlWithPath[1].length > 0 && urlWithPath[1].length <= 32) {
    roomId = urlWithPath[1].trim();
  }
  if (urlWithPath.length > 2 && urlWithPath[2].length > 0 && urlWithPath[2].length <= 32) {
    pwd = urlWithPath[2].trim();
  }
  if (roomId === 'ws') {  // 兼容旧版本
    roomId = null;
  }
  if (roomId === '') {
    roomId = null;
  }
  let turns = null;
  if (roomId) {
    // 校验密码是否匹配
    if (!pwd || !roomPwd[roomId] || roomPwd[roomId].pwd.toLowerCase() !== pwd.toLowerCase()) {
      roomId = null;
    } else {
      turns = turn;  // 允许加入，获取 TURN 服务器信息
    }
  }


  const currentId = service.registerUser(ip, roomId, socket);
  // 向客户端发送自己的id
  socketSend_UserId(socket, currentId, roomId, turns);
  
  console.log(`${currentId}@${ip}${roomId ? '/' + roomId : ''} connected`);
  
  service.getUserList(ip, roomId).forEach(user => {
    socketSend_RoomInfo(user.socket, ip, roomId);
  });

  socketSend_JoinedRoom(socket, currentId);
  

  socket.on('message', (msg, isBinary) => {
    const msgStr = msg.toString();
    if (!msgStr || msgStr.length > 1024 * 10) {
      return;
    }
    let message = null;
    try {
      message = JSON.parse(msgStr);
    } catch (e) {
      console.error('Invalid JSON', msgStr);
      message = null;
    }

    const { uid, targetId, type, data } = message;
    if (!type || !uid || !targetId) {
      return null;
    }
    const me = service.getUser(ip, roomId, uid)
    const target = service.getUser(ip, roomId, targetId)
    if (!me || !target) {
      return;
    }

    if (type === RECEIVE_TYPE_NEW_CANDIDATE) {
      socketSend_Candidate(target.socket, { targetId: uid, candidate: data.candidate });
      return;
    }
    if (type === RECEIVE_TYPE_NEW_CONNECTION) {
      socketSend_ConnectInvite(target.socket, { targetId: uid, offer: data.targetAddr });
      return;
    }
    if (type === RECEIVE_TYPE_CONNECTED) {
      socketSend_Connected(target.socket, { targetId: uid, answer: data.targetAddr });
      return;
    }
    if (type === RECEIVE_TYPE_KEEPALIVE) {
      return;
    }
    if (type === RECEIVE_TYPE_UPDATE_NICKNAME) {
      const success = service.updateNickname(ip, roomId, uid, data.nickname);
      if (success) {
        // 通知所有用户昵称更新
        service.getUserList(ip, roomId).forEach(user => {
          socketSend_NicknameUpdated(user.socket, { id: uid, nickname: data.nickname });
        });
      }
      return;
    }
    
  });

  socket.on('close', () => {
    service.unregisterUser(ip, roomId, currentId);
    service.getUserList(ip, roomId).forEach(user => {
      socketSend_RoomInfo(user.socket, ip, roomId);
    });
    console.log(`${currentId}@${ip}${roomId ? '/' + roomId : ''} disconnected`);
  });

  socket.on('error', () => {
    service.unregisterUser(ip, roomId, currentId);
    service.getUserList(ip, roomId).forEach(user => {
      socketSend_RoomInfo(user.socket, ip, roomId);
    });
    console.log(`${currentId}@${ip}${roomId ? '/' + roomId : ''} disconnected`);
  });
});

const express = require('express');
const crypto = require('crypto'); // 引入 crypto 模块进行 MD5 加密
const app = express();

app.use(express.json()); // 允许解析 JSON 数据

// 中间件：验证 API Key
const authenticateApiKey = (req, res, next) => {
  const requestApiKey = req.headers['x-api-key']; // 从请求头获取 API 密钥
  let s = md5Hash(requestApiKey);
  if (!s || s !== apiKey) {
    return res.status(403).json({ error: '无效的 API 密钥' });
  }
  next(); // 验证通过，继续执行请求
};

// 获取所有房间
app.get('/rooms', authenticateApiKey, (req, res) => {
  res.json(roomPwd);
});

// 添加新房间
app.post('/room', authenticateApiKey, (req, res) => {
  const { roomId, pwd } = req.body;
  if (!roomId || !pwd) {
    return res.status(400).json({ error: '房间 ID 和密码不能为空' });
  }

  // 进行 MD5 加密
  const hashedPwd = md5Hash(pwd);

  addRoom(roomId, hashedPwd);
  res.json({ success: true, message: `房间 ${roomId} 已添加` });
});

// 更新房间信息（修改密码）
app.put('/room/:roomId', authenticateApiKey, (req, res) => {
  const { roomId } = req.params;
  const { pwd } = req.body;

  if (!pwd) {
    return res.status(400).json({ error: '密码不能为空' });
  }

  // 进行 MD5 加密
  const hashedPwd = md5Hash(pwd);

  if (updateRoom(roomId, hashedPwd)) {
    res.json({ success: true, message: `房间 ${roomId} 已更新` });
  } else {
    res.status(404).json({ error: `房间 ${roomId} 不存在` });
  }
});

// 删除房间
app.delete('/room/:roomId', authenticateApiKey, (req, res) => {
  const { roomId } = req.params;
  if (deleteRoom(roomId)) {
    res.json({ success: true, message: `房间 ${roomId} 已删除` });
  } else {
    res.status(404).json({ error: `房间 ${roomId} 不存在` });
  }
});


// MD5 加密函数
function md5Hash(text) {
  return crypto.createHash('md5').update(text).digest('hex');
}

// 添加房间
function addRoom(roomId, pwd) {
  roomPwd[roomId] = { pwd };
  console.log(`新房间已添加: ${roomId}, 密码: ${pwd}`);
}

// 更新房间
function updateRoom(roomId, newPwd) {
  if (roomPwd[roomId]) {
    roomPwd[roomId].pwd = newPwd;
    console.log(`房间 ${roomId} 密码已更新`);
    return true;
  }
  return false;
}

// 删除房间
function deleteRoom(roomId) {
  if (roomPwd[roomId]) {
    delete roomPwd[roomId];
    console.log(`房间 ${roomId} 已删除`);
    return true;
  }
  return false;
}

app.listen(8003, () => console.log('房间管理 API 运行在 http://localhost:8003'));


// 发送 WebSocket 消息的工具函数
function send(socket, type, data) {
  socket.send(JSON.stringify({ type, data }));
}

// WebSocket 相关的发送方法
function socketSend_UserId(socket, id, roomId, turns) {
  send(socket, SEND_TYPE_REG, { id, roomId, turns });
}
function socketSend_RoomInfo(socket, ip, roomId) {
  const result = service.getUserList(ip, roomId).map(user => ({
    id: user.id,
    nickname: user.nickname
  }));
  send(socket, SEND_TYPE_ROOM_INFO, result);
}
function socketSend_JoinedRoom(socket, id) {
  send(socket, SEND_TYPE_JOINED_ROOM, { id });
}
function socketSend_Candidate(socket, data) {
  send(socket, SEND_TYPE_NEW_CANDIDATE, data);
}
function socketSend_ConnectInvite(socket, data) {
  send(socket, SEND_TYPE_NEW_CONNECTION, data);
}
function socketSend_Connected(socket, data) {
  send(socket, SEND_TYPE_CONNECTED, data);
}
function socketSend_NicknameUpdated(socket, data) {
  send(socket, SEND_TYPE_NICKNAME_UPDATED, data);
}
